/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <string>
#include <map>
#include <memory>

namespace El {
namespace Upgrade {

// 分区标识
enum class BootSlot { SLOT_A, SLOT_B, UNKNOWN };

// 启动状态
enum class BootStatus {
    SUCCESSFUL, // 启动成功
    FAILED,     // 启动失败
    UNKNOWN     // 未知状态
};

/**
 * @brief U-Boot环境变量管理器，用于A/B分区切换
 */
class UBootEnvManager {
public:
    UBootEnvManager();
    ~UBootEnvManager();

    /**
     * @brief 获取当前启动分区
     * @return 当前启动的分区
     */
    BootSlot GetCurrentBootSlot();

    /**
     * @brief 获取启动分区信息
     * @return JSON格式的分区信息字符串
     */
    std::string GetBootSlotInfo();

    /**
     * @brief 获取非活跃分区
     * @return 非活跃的分区
     */
    BootSlot GetInactiveBootSlot();

    /**
     * @brief 设置下次启动分区
     * @param slot 目标分区
     * @return 是否成功
     */
    bool SetBootSlot(BootSlot slot);

    /**
     * @brief 切换启动分区
     * @param slot 目标分区
     * @return 是否成功
     */
    bool SwitchBootSlot(BootSlot slot);

    /**
     * @brief 标记当前启动为成功
     * @return 是否成功
     */
    bool MarkBootSuccessful();

    /**
     * @brief 重置启动计数器
     * @return 是否成功
     */
    bool ResetBootCount();

    /**
     * @brief 获取启动计数器值
     * @return 启动计数器值，失败返回-1
     */
    int GetBootCount();

    /**
     * @brief 获取最大启动重试次数
     * @return 最大重试次数，失败返回-1
     */
    int GetMaxBootCount();

    /**
     * @brief 设置最大启动重试次数
     * @param count 最大重试次数
     * @return 是否成功
     */
    bool SetMaxBootCount(int count);

    /**
     * @brief 检查启动是否成功
     * @return 启动状态
     */
    BootStatus GetBootStatus();

    /**
     * @brief 获取环境变量值
     * @param name 变量名
     * @return 变量值，失败返回空字符串
     */
    std::string GetEnvVar(const std::string &name);

    /**
     * @brief 设置环境变量值
     * @param name 变量名
     * @param value 变量值
     * @return 是否成功
     */
    bool SetEnvVar(const std::string &name, const std::string &value);

    /**
     * @brief 删除环境变量
     * @param name 变量名
     * @return 是否成功
     */
    bool DeleteEnvVar(const std::string &name);

    /**
     * @brief 获取所有环境变量
     * @return 环境变量映射表
     */
    std::map<std::string, std::string> GetAllEnvVars();

    /**
     * @brief 打印当前分区状态信息
     */
    void PrintBootInfo();

    /**
     * @brief 验证分区配置的完整性
     * @return 是否配置正确
     */
    bool ValidateBootConfig();

    /**
     * @brief 强制切换到指定分区（紧急恢复用）
     * @param slot 目标分区
     * @return 是否成功
     */
    bool ForceBootSlot(BootSlot slot);

public:
    /**
     * @brief 将分区枚举转换为字符串
     * @param slot 分区枚举
     * @return 分区字符串
     */
    std::string BootSlotToString(BootSlot slot);

private:
    /**
     * @brief 将字符串转换为分区枚举
     * @param str 分区字符串
     * @return 分区枚举
     */
    BootSlot StringToBootSlot(const std::string &str);

private:
    // fw_printenv/fw_setenv 命令是否可用
    bool fw_available_ = false;

    // U-Boot环境变量名称常量
    static constexpr const char *ENV_BOOT_SLOT = "boot_slot";
    static constexpr const char *ENV_BOOT_COUNT = "boot_count";
    static constexpr const char *ENV_BOOT_SUCCESSFUL = "boot_successful";
    static constexpr const char *ENV_MAX_BOOT_COUNT = "max_boot_count";
};

} // namespace Upgrade
} // namespace El